wikilink 插件
自研的 VitePress 插件,把 Obsidian 风格的 <span class="wikilink-dead" title="未找到: 页面名" style="color:#c33;border-bottom:1px dashed #c33">页面名</span> 双链语法,在静态站构建时自动转成 VitePress 可点击的内部链接。
源码位置:/opt/wiki-site/docs/.vitepress/wikilink-plugin.mjs(部署在 ECS)
它解决什么问题
<span class="wikilink-dead" title="未找到: wikilink" style="color:#c33;border-bottom:1px dashed #c33">wikilink</span> 是 Obsidian 的核心语法,让人写笔记时只需要管"链到哪页"而不管"具体 URL"。但 VitePress 默认不认这个语法,会把 [Hermes Agents](/entities/Hermes%20Agents) 当成普通文字渲染。
如果不解决,团队就要在两个语法之间二选一:
- 用
<span class="wikilink-dead" title="未找到: xxx" style="color:#c33;border-bottom:1px dashed #c33">xxx</span>→ Obsidian 可点,wiki.86lux.net 死链 - 用
[xxx](xxx.md)→ wiki.86lux.net 可点,Obsidian 失去图谱视图
插件的存在让两边都可点,Obsidian 与 VitePress 双兼容。
它怎么工作
markdown 输入:
本系统由 [Hermes Agents](/entities/Hermes%20Agents) 消费 [GitHub](/entities/GitHub) 上的 wiki。
插件运行时(VitePress build 阶段):
1. 扫描整个 docs/ 目录,建一个 "页面名 → URL" 映射表
例:Hermes Agents → /entities/Hermes%20Agents
GitHub → /entities/GitHub
2. 对每个 markdown 文件,正则匹配 <span class="wikilink-dead" title="未找到: xxx" style="color:#c33;border-bottom:1px dashed #c33">xxx</span> 或 <span class="wikilink-dead" title="未找到: xxx" style="color:#c33;border-bottom:1px dashed #c33">alias</span>
3. 替换为 markdown 内联链接:
[Hermes Agents](/entities/Hermes%20Agents) → [Hermes Agents](/entities/Hermes%20Agents)
4. URL 路径段做 encodeURIComponent,保证含空格/中文的页名也能正确生成 URL
5. 找不到的 wikilink 渲染为带红色虚线的 <span class="wikilink-dead">,
visual flag 提示作者"这是个死链"
最终 HTML:
<p>本系统由 <a href="/entities/Hermes%20Agents">Hermes Agents</a>
消费 <a href="/entities/GitHub">GitHub</a> 上的 wiki。</p>关键设计
- 构建时一次性扫描:不是运行时算,对静态站性能零影响
- basename 兜底:找不到精确路径时降级为按文件 basename 查找
- 死链不挂掉构建:用红虚线视觉提示,但不报错,作者改完再 build
- URL 编码兼容:含空格的页名(如
Hermes Agents)会被编码为Hermes%20Agents,VitePress markdown 渲染才能正确生成<a>标签
调试历史
部署当天踩过两个坑:
坑 1:build 失败 "Element is missing end tag"
某份 markdown 文件里有 <rel>、<分类> 这种文本占位符,被 Vue 的 markdown 编译器误认为 HTML 标签,没找到闭合。
修复:fix-angle-brackets.py 把所有 <xxx> 字面占位符替换为 〈xxx〉(中文角括号),既保留语义又不被 HTML 解析器吞。
坑 2:wikilink 含空格不渲染为链接
[Hermes Agents](/entities/Hermes%20Agents) → 插件正确转出 [Hermes Agents](Hermes Agents),但 markdown 渲染器看到 URL 里有空格,不当成链接。
修复:在插件里对 URL 路径段调用 encodeURIComponent:
const safeUrl = url.split('/').map(s => s ? encodeURIComponent(s) : s).join('/')
return `[${display}](${safeUrl})`它不是什么
- ❌ 不是 VitePress 官方插件(自研,不在 npm 上)
- ❌ 不替代 markdown-it 的 link 解析(只在 link 解析之前做替换,把 wikilink 转成标准 markdown link 后让 markdown-it 自己处理)
- ❌ 不影响 Obsidian 的渲染(Obsidian 自己有原生 wikilink 支持,与本插件互不干扰)
关联
- VitePress — 渲染引擎
- Docs-as-Code 发布架构 — 整体架构里的渲染层
- GitHub — 插件源码所在仓库(ECS 上)